#pragma once

#include <iterator>

#include "../utils/misc.h"

namespace mdtx::online::collector
{
    // TODO: ??? poly based on iterator type ???
    template <typename TimeIter, typename ScalaIter, size_t Nin, size_t Nout>
    class collector_base
    {
    public:
        using time_iter = TimeIter;
        using scala_iter = ScalaIter;
        using time_type = typename std::iterator_traits<time_iter>::value_type;
        using scala_type = typename std::iterator_traits<scala_iter>::value_type;

        using tuple_in = time_ntuple<time_type, scala_type, Nin>;
        using tuple_out = time_ntuple<time_iter, scala_iter, Nout>;

        constexpr static size_t num_in = Nin + 1;
        constexpr static size_t num_vin = Nin;
        constexpr static size_t num_out = Nout + 1;
        constexpr static size_t num_vout = Nout;

    public:
        virtual size_t update(tuple_in const &) = 0;
        virtual size_t size() const = 0;
        virtual void collect(tuple_out &) = 0;

        template <typename... Ts>
        size_t update(Ts... in)
        {
            static_assert(sizeof...(Ts) == num_in, "Incorrect number of input.");
            return update(tuple_in(in));
        }

        template <typename... Iters>
        void collect(Iters... out)
        {
            static_assert(sizeof...(Iters) == num_out, "Incorrect number of output.");
            collect(tuple_out(out...));
        }

        virtual ~collector_base() = default;
    };
}
